package com.example.orderservice.actor;

import akka.actor.AbstractPersistentActor;
import akka.actor.Props;
import akka.event.Logging;
import akka.event.LoggingAdapter;
import akka.persistence.SnapshotOffer;
import com.example.orderservice.entity.OutboxEvent;
import com.example.orderservice.event.*;
import com.example.orderservice.repository.OutboxEventRepository;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionSynchronizationManager;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

/**
 * 持久化订单Actor
 * 实现事件溯源模式，所有状态变更都通过事件记录
 */
@Component("persistentOrderActor")
@Scope("prototype")
public class PersistentOrderActor extends AbstractPersistentActor {

    private final LoggingAdapter log = Logging.getLogger(getContext().getSystem(), this);
    
    @Autowired
    private OutboxEventRepository outboxEventRepository;
    
    @Autowired
    private ObjectMapper objectMapper;
    
    private OrderState state = new OrderState();
    
    public static Props props() {
        return Props.create(PersistentOrderActor.class);
    }
    
    @Override
    public String persistenceId() {
        return "order-" + getSelf().path().name();
    }
    
    @Override
    public Receive createReceive() {
        return receiveBuilder()
                .match(CreateOrder.class, this::handleCreateOrder)
                .match(PayOrder.class, this::handlePayOrder)
                .match(CancelOrder.class, this::handleCancelOrder)
                .match(GetOrderStatus.class, this::handleGetOrderStatus)
                .matchAny(o -> log.warning("收到未知消息: {}", o))
                .build();
    }
    
    @Override
    public Receive createReceiveRecover() {
        return receiveBuilder()
                .match(OrderCreatedEvent.class, this::handleOrderCreatedEvent)
                .match(OrderPaidEvent.class, this::handleOrderPaidEvent)
                .match(OrderCancelledEvent.class, this::handleOrderCancelledEvent)
                .match(SnapshotOffer.class, ss -> {
                    log.info("恢复快照: {}", ss);
                    state = (OrderState) ss.snapshot();
                })
                .build();
    }
    
    /**
     * 处理创建订单命令
     */
    private void handleCreateOrder(CreateOrder createOrder) {
        log.info("处理创建订单请求: {}", createOrder.getOrderId());
        
        if (state.getStatus() != null) {
            log.warning("订单已存在: {}", createOrder.getOrderId());
            getSender().tell(new OrderCreated(createOrder.getOrderId(), "ALREADY_EXISTS"), getSelf());
            return;
        }
        
        try {
            // 创建订单创建事件
            OrderCreatedEvent event = new OrderCreatedEvent(
                createOrder.getOrderId(),
                createOrder.getCustomerId(),
                createOrder.getItems(),
                createOrder.getTotalAmount()
            );
            
            // 持久化事件
            persist(event, evt -> {
                // 事件持久化成功后的回调
                handleOrderCreatedEvent(evt);
                
                // 保存到 Outbox 表
                saveToOutbox(event);
                
                // 保存快照（每10个事件保存一次）
                if (lastSequenceNr() % 10 == 0) {
                    saveSnapshot(state);
                }
                
                log.info("订单创建成功，事件已持久化: {}", createOrder.getOrderId());
                getSender().tell(new OrderCreated(createOrder.getOrderId(), "SUCCESS"), getSelf());
            });
            
        } catch (Exception e) {
            log.error("创建订单失败: {}", e.getMessage(), e);
            getSender().tell(new OrderCreated(createOrder.getOrderId(), "FAILED"), getSelf());
        }
    }
    
    /**
     * 处理支付订单命令
     */
    private void handlePayOrder(PayOrder payOrder) {
        log.info("处理支付订单请求: {}", payOrder.getOrderId());
        
        if (state.getStatus() == null) {
            log.warning("订单不存在: {}", payOrder.getOrderId());
            getSender().tell(new OrderPaid(payOrder.getOrderId(), "ORDER_NOT_FOUND"), getSelf());
            return;
        }
        
        if (!"CREATED".equals(state.getStatus())) {
            log.warning("订单状态不允许支付: {} 当前状态: {}", payOrder.getOrderId(), state.getStatus());
            getSender().tell(new OrderPaid(payOrder.getOrderId(), "INVALID_STATUS"), getSelf());
            return;
        }
        
        try {
            // 创建订单支付事件
            OrderPaidEvent event = new OrderPaidEvent(
                payOrder.getOrderId(),
                payOrder.getPaymentId(),
                payOrder.getPaymentMethod(),
                payOrder.getAmount()
            );
            
            // 持久化事件
            persist(event, evt -> {
                handleOrderPaidEvent(evt);
                saveToOutbox(event);
                
                if (lastSequenceNr() % 10 == 0) {
                    saveSnapshot(state);
                }
                
                log.info("订单支付成功，事件已持久化: {}", payOrder.getOrderId());
                getSender().tell(new OrderPaid(payOrder.getOrderId(), "SUCCESS"), getSelf());
            });
            
        } catch (Exception e) {
            log.error("支付订单失败: {}", e.getMessage(), e);
            getSender().tell(new OrderPaid(payOrder.getOrderId(), "FAILED"), getSelf());
        }
    }
    
    /**
     * 处理取消订单命令
     */
    private void handleCancelOrder(CancelOrder cancelOrder) {
        log.info("处理取消订单请求: {}", cancelOrder.getOrderId());
        
        if (state.getStatus() == null) {
            log.warning("订单不存在: {}", cancelOrder.getOrderId());
            getSender().tell(new OrderCancelled(cancelOrder.getOrderId(), "ORDER_NOT_FOUND"), getSelf());
            return;
        }
        
        if ("CANCELLED".equals(state.getStatus()) || "PAID".equals(state.getStatus())) {
            log.warning("订单状态不允许取消: {} 当前状态: {}", cancelOrder.getOrderId(), state.getStatus());
            getSender().tell(new OrderCancelled(cancelOrder.getOrderId(), "INVALID_STATUS"), getSelf());
            return;
        }
        
        try {
            // 创建订单取消事件
            OrderCancelledEvent event = new OrderCancelledEvent(
                cancelOrder.getOrderId(),
                cancelOrder.getReason()
            );
            
            // 持久化事件
            persist(event, evt -> {
                handleOrderCancelledEvent(evt);
                saveToOutbox(event);
                
                if (lastSequenceNr() % 10 == 0) {
                    saveSnapshot(state);
                }
                
                log.info("订单取消成功，事件已持久化: {}", cancelOrder.getOrderId());
                getSender().tell(new OrderCancelled(cancelOrder.getOrderId(), "SUCCESS"), getSelf());
            });
            
        } catch (Exception e) {
            log.error("取消订单失败: {}", e.getMessage(), e);
            getSender().tell(new OrderCancelled(cancelOrder.getOrderId(), "FAILED"), getSelf());
        }
    }
    
    /**
     * 处理获取订单状态命令
     */
    private void handleGetOrderStatus(GetOrderStatus getOrderStatus) {
        log.info("获取订单状态: {}", getOrderStatus.getOrderId());
        getSender().tell(new OrderStatus(state), getSelf());
    }
    
    /**
     * 处理订单创建事件（状态更新）
     */
    private void handleOrderCreatedEvent(OrderCreatedEvent event) {
        state.setOrderId(event.getOrderId());
        state.setCustomerId(event.getCustomerId());
        state.setItems(event.getItems());
        state.setTotalAmount(event.getTotalAmount());
        state.setStatus("CREATED");
        state.setCreatedAt(LocalDateTime.now());
        
        log.info("订单状态已更新为 CREATED: {}", event.getOrderId());
    }
    
    /**
     * 处理订单支付事件（状态更新）
     */
    private void handleOrderPaidEvent(OrderPaidEvent event) {
        state.setStatus("PAID");
        state.setPaymentId(event.getPaymentId());
        state.setPaymentMethod(event.getPaymentMethod());
        state.setPaidAt(LocalDateTime.now());
        
        log.info("订单状态已更新为 PAID: {}", event.getOrderId());
    }
    
    /**
     * 处理订单取消事件（状态更新）
     */
    private void handleOrderCancelledEvent(OrderCancelledEvent event) {
        state.setStatus("CANCELLED");
        state.setCancellationReason(event.getReason());
        state.setCancelledAt(LocalDateTime.now());
        
        log.info("订单状态已更新为 CANCELLED: {}", event.getOrderId());
    }
    
    /**
     * 保存事件到 Outbox 表
     */
    private void saveToOutbox(OrderEvent event) {
        try {
            String eventData = objectMapper.writeValueAsString(event);
            
            OutboxEvent outboxEvent = new OutboxEvent();
            outboxEvent.setAggregateId(event.getOrderId());
            outboxEvent.setAggregateType("Order");
            outboxEvent.setEventType(event.getEventType());
            outboxEvent.setEventData(eventData);
            outboxEvent.setCreatedAt(LocalDateTime.now());
            outboxEvent.setProcessed(false);
            outboxEvent.setRetryCount(0);
            outboxEvent.setMaxRetries(3);
            
            outboxEventRepository.save(outboxEvent);
            
            log.info("事件已保存到 Outbox: 订单ID={}, 事件类型={}", event.getOrderId(), event.getEventType());
            
        } catch (Exception e) {
            log.error("保存事件到 Outbox 失败: {}", e.getMessage(), e);
            throw new RuntimeException("保存事件到 Outbox 失败", e);
        }
    }
    
    // 命令消息类
    public static class CreateOrder {
        private String orderId;
        private String customerId;
        private List<OrderItem> items;
        private Double totalAmount;

        public CreateOrder(String orderId, String customerId, List<OrderItem> items, Double totalAmount) {
            this.orderId = orderId;
            this.customerId = customerId;
            this.items = items;
            this.totalAmount = totalAmount;
        }

        public String getOrderId() { return orderId; }
        public String getCustomerId() { return customerId; }
        public List<OrderItem> getItems() { return items; }
        public Double getTotalAmount() { return totalAmount; }
    }

    public static class PayOrder {
        private String orderId;
        private String paymentId;
        private String paymentMethod;
        private Double amount;

        public PayOrder(String orderId, String paymentId, String paymentMethod, Double amount) {
            this.orderId = orderId;
            this.paymentId = paymentId;
            this.paymentMethod = paymentMethod;
            this.amount = amount;
        }

        public String getOrderId() { return orderId; }
        public String getPaymentId() { return paymentId; }
        public String getPaymentMethod() { return paymentMethod; }
        public Double getAmount() { return amount; }
    }

    public static class CancelOrder {
        private String orderId;
        private String reason;

        public CancelOrder(String orderId, String reason) {
            this.orderId = orderId;
            this.reason = reason;
        }

        public String getOrderId() { return orderId; }
        public String getReason() { return reason; }
    }
    
    public static class GetOrderStatus {
        private String orderId;
        
        public GetOrderStatus(String orderId) {
            this.orderId = orderId;
        }
        
        public String getOrderId() { return orderId; }
    }

    // 响应消息类
    public static class OrderCreated {
        private String orderId;
        private String status;

        public OrderCreated(String orderId, String status) {
            this.orderId = orderId;
            this.status = status;
        }

        public String getOrderId() { return orderId; }
        public String getStatus() { return status; }
    }

    public static class OrderPaid {
        private String orderId;
        private String status;

        public OrderPaid(String orderId, String status) {
            this.orderId = orderId;
            this.status = status;
        }

        public String getOrderId() { return orderId; }
        public String getStatus() { return status; }
    }

    public static class OrderCancelled {
        private String orderId;
        private String status;

        public OrderCancelled(String orderId, String status) {
            this.orderId = orderId;
            this.status = status;
        }

        public String getOrderId() { return orderId; }
        public String getStatus() { return status; }
    }
    
    public static class OrderStatus {
        private OrderState state;
        
        public OrderStatus(OrderState state) {
            this.state = state;
        }
        
        public OrderState getState() { return state; }
    }
    
    // 订单状态类
    public static class OrderState {
        private String orderId;
        private String customerId;
        private List<OrderItem> items = new ArrayList<>();
        private Double totalAmount;
        private String status;
        private String paymentId;
        private String paymentMethod;
        private String cancellationReason;
        private LocalDateTime createdAt;
        private LocalDateTime paidAt;
        private LocalDateTime cancelledAt;
        
        // Getters and Setters
        public String getOrderId() { return orderId; }
        public void setOrderId(String orderId) { this.orderId = orderId; }
        
        public String getCustomerId() { return customerId; }
        public void setCustomerId(String customerId) { this.customerId = customerId; }
        
        public List<OrderItem> getItems() { return items; }
        public void setItems(List<OrderItem> items) { this.items = items; }
        
        public Double getTotalAmount() { return totalAmount; }
        public void setTotalAmount(Double totalAmount) { this.totalAmount = totalAmount; }
        
        public String getStatus() { return status; }
        public void setStatus(String status) { this.status = status; }
        
        public String getPaymentId() { return paymentId; }
        public void setPaymentId(String paymentId) { this.paymentId = paymentId; }
        
        public String getPaymentMethod() { return paymentMethod; }
        public void setPaymentMethod(String paymentMethod) { this.paymentMethod = paymentMethod; }
        
        public String getCancellationReason() { return cancellationReason; }
        public void setCancellationReason(String cancellationReason) { this.cancellationReason = cancellationReason; }
        
        public LocalDateTime getCreatedAt() { return createdAt; }
        public void setCreatedAt(LocalDateTime createdAt) { this.createdAt = createdAt; }
        
        public LocalDateTime getPaidAt() { return paidAt; }
        public void setPaidAt(LocalDateTime paidAt) { this.paidAt = paidAt; }
        
        public LocalDateTime getCancelledAt() { return cancelledAt; }
        public void setCancelledAt(LocalDateTime cancelledAt) { this.cancelledAt = cancelledAt; }
    }
}
